//    网络反应器
#pragma once
#include <string>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <map>
#include <vector>
#include <assert.h>
#ifndef WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/thread.h>
#include "WorkerThread.h"
#include "CRC32.h"
#include "sync.h"

#pragma warning(disable:4100)

//    单个包的最大长度为10M
#define PACKAGE_MAX_LEN 10485760
//    包开始标识
#define START_FLAG 0x00FFFF00
//    每个bufferevent写入缓冲区上限(50M)
#define WRITE_BUFF_MAX 52428800


//    bufferevent自动锁
class AutoBuffereventLock
{
public:
    AutoBuffereventLock(bufferevent *bev)
        : _bev(bev)
    {
        if (_bev != NULL)
            bufferevent_lock(_bev);
    }
    ~AutoBuffereventLock()
    {
        if (_bev != NULL)
            bufferevent_unlock(_bev);
    }
    
    bufferevent *_bev;
};

//    单体模板类。
template< typename T >
class CSingleton
{
public:
    static T* Instance(void)
    {
        static T singleton;
        return & singleton;
    }

    ~CSingleton(void)
    {
    }

    CSingleton(void)
    {
    }
};

//    网络连接信息
struct NETWORK_INFO
{
    short _family;            //    协议类型
    unsigned short _port;    //    端口
    std::string _ip;

    NETWORK_INFO()
        : _family(0)
        , _port(0)
    {
    }

    NETWORK_INFO(const NETWORK_INFO &right)
    {
        *this = right;
    }

    ~NETWORK_INFO()
    {
    }

    NETWORK_INFO& operator=(const NETWORK_INFO &right)
    {
        _family = right._family;
        _port = right._port;
        _ip = right._ip;
        return *this;
    }

    bool operator==(const NETWORK_INFO &right)
    {
        return _family == right._family && _port == right._port && _ip == right._ip;
    }

    //    必须为严格意义的大于，在map.find中会做正反验证，如果恒为一个值则会出错"invalid operator<"
    bool operator < (const NETWORK_INFO &right) const 
    {
        if (_ip < right._ip)
        {
          return true;
        }
        else if (_ip == right._ip)
        {
            if (_port < right._port)
                return true;
            else
                return false;
        }
        else
        {
          return false;
        }
    }
};

//    网络连接列表
typedef std::vector<NETWORK_INFO> VEC_NETWORK_INFO;

#pragma pack(push,1)
//    网络数据
struct NETWORK_DATA
{
    unsigned long _flag;    //    数据包起始标记:START_FLAG
    unsigned long _type;    //    数据包类型
    unsigned long _len;        //    buffer大小
    unsigned char *_buffer;    //    buffer指针
    unsigned long _crc32;    //    buffer  crc32校验

    NETWORK_DATA()
        : _flag(START_FLAG)
        , _type(0)
        , _len(0)
        , _buffer(NULL)
        , _crc32(0)
    {
    }
    
    ~NETWORK_DATA()
    {
    }

    NETWORK_DATA& operator=(const NETWORK_DATA &right)
    {
        _flag = right._flag;
        _type = right._type;
        _len = right._len;
        _buffer = right._buffer;
        _crc32 = right._crc32;
        return *this;
    }
};
#pragma pack(pop)

//    回调函数声明

//    关闭连接消息回调
void CloseEventCallbackFun(evutil_socket_t fd, short event, void *arg);

//    监听回调
void ListenerEventCallbackFun(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *user_data);

//    读回调(接收数据)
void ReadCallbackFun(struct bufferevent *bev, void *ctx);

//    写回调(发送数据)
void WriteCallbackFun(struct bufferevent *bev, void *ctx);

//    事件回调
void EventCallbackFun(struct bufferevent *bev, short what, void *ctx);


//    网络输入输出处理类
class CNetworkReactor;
class CNetworkIO
{
    //    函数部分
public:
    CNetworkIO();

    CNetworkIO(CNetworkIO &right);    

    virtual ~CNetworkIO();

    //    向对应的网络写数据
    bool write(NETWORK_DATA &network_data);
    
    //    获取网络信息
    inline NETWORK_INFO& GetNetworkInfo() 
    {
        return _network_info;
    }    

    // 关闭连接
    bool Colse();

    //    获取错误信息(获取当前最后一次的错误描述)
    inline std::string GetError() 
    {
        Process::CAutoLock    lock(&_cs_err);
        return _err;
    }

    //    获取本地服务器在本连接中监听端口号
    inline unsigned long GetListerPort() 
    {
        return _listener_port;
    }

    //    判断连接是否断开(ture断开， false连接)
    inline bool IsOff()
    {
        return _off;
    }

protected:
    //    读取网络上的数据(回调)
    virtual bool read(NETWORK_DATA* network_data) = 0;

    //    网络事件(回调)
    //    事件类型
    //#define BEV_EVENT_READING    0x01    /**< error encountered while reading */
    //#define BEV_EVENT_WRITING    0x02    /**< error encountered while writing */
    //#define BEV_EVENT_EOF        0x10    /**< eof file reached */
    //#define BEV_EVENT_ERROR        0x20    /**< unrecoverable error encountered */
    //#define BEV_EVENT_TIMEOUT    0x40    /**< user-specified timeout reached */
    //#define BEV_EVENT_CONNECTED    0x80    /**< connect operation finished. */
    virtual bool event(short events) = 0;

private:
    CNetworkIO& operator=(CNetworkIO &right);

    //    建立连接
    //    客户模式
    bool Open(NETWORK_INFO network_info, bufferevent *bev, CNetworkReactor *reactor);
    //    服务端模式
    bool Open(NETWORK_INFO network_info, bufferevent *bev, CNetworkReactor *reactor, unsigned short lister_port);

    //    读回调(接收数据)
    void ReadCallback(bufferevent *bev, void *user_data);

    //    写回调(发送数据)
    void WriteCallback(bufferevent *bev, void *user_data);

    //    事件回调
    void EventCallback(bufferevent *bev, short events, void *user_data);

    //    获取bufferevnet
    inline bufferevent* GetBufferevent()
    {
        return _bev;
    }

    //    获取引用计数器值
    inline long GetRef()
    {
        Process::CAutoLock    lock(&_cs_ref_count);
        return _ref_count;
    }

    //    引用计数器加1
    inline bool AddRef()
    {
        Process::CAutoLock    lock(&_cs_ref_count);
        ++_ref_count;
        return true;
    }

    //    引用计数器减1
    inline bool SubRef()
    {
        Process::CAutoLock    lock(&_cs_ref_count);
        --_ref_count;
        return false;
    }

    //    设置错误信息(设置为当前最后一次的错误描述)
    inline void SetError(char *err) 
    {
        Process::CAutoLock    lock(&_cs_err);
        _err = err;
    }

    friend class CNetworkReactor;
    friend void ReadCallbackFun(struct bufferevent *bev, void *ctx);
    friend void WriteCallbackFun(struct bufferevent *bev, void *ctx);
    friend void EventCallbackFun(struct bufferevent *bev, short what, void *ctx);

    //    数据部分
public:
protected:
private:
    NETWORK_INFO        _network_info;
    bufferevent            *_bev;
    CNetworkReactor        *_reactor;

    Process::CCriticalSection    _cs_err;    //    错误字符串锁
    std::string                    _err;

    unsigned short                _type;                //    本地sokcet类型 0:服务器 1:客户端
    unsigned short                _listener_port;        //    本地监听端口(类型为服务器时有效)

    Process::CCriticalSection    _cs_ref_count;        //    引用计数器锁
    long                        _ref_count;            //    引用计数器(当引用计数器小于等于0时表示可以销毁此对象)

    bool                        _off;                //    网络是否已断开(ture已经断开, false为断开)
};

//    监听基础
class LISTENER_INFO_BASE
{
public:
    unsigned short    _port;                        //    监听端口
    void            *_network_io;                //    数据处理类指针

    LISTENER_INFO_BASE()
        : _port(0)
        , _network_io(NULL)
    {;}

    virtual ~LISTENER_INFO_BASE() 
    {
        if (_network_io != NULL)
        {
            delete _network_io;
            _network_io = NULL;
        }
    }
    virtual void *DefaultAllocationNetworkIO() = 0;
};

//    监听参数
template <typename T>
class LISTENER_INFO :public LISTENER_INFO_BASE
{
public:
    LISTENER_INFO()    {;}
    ~LISTENER_INFO() {;}

    //    new 一个模板类型对象,并以_network_io初始化
    void *DefaultAllocationNetworkIO() 
    {
        T *p_network_io = (T*)_network_io;
        return new T(*p_network_io);
    }
};

//    网络反应器类
class CNetworkReactor
    : public Process::CWorkerThread
{
    //    函数部分
public:
    CNetworkReactor();

    virtual ~CNetworkReactor();

    //    启动反应器
    bool Start();

    //    发送停止反应器信号
    bool Stop();

    //    添加连接事件(暂时不支持协议选择,固定为TCP. 注意:p_network_io禁止类型转换，必须为原类型指针)
    //    服务模式
    template<typename T> 
    bool AddConnectEvent(unsigned short port, T *p_network_io)
    {
        {
            Process::CAutoLock    lock(&_cs_map_listener);
            std::map<evconnlistener*, LISTENER_INFO_BASE*>::iterator it_listener = _map_listener.begin();
            if (it_listener != _map_listener.end())
            {
                SetError("此端口已经监听.");
                return false;
            }
        }

        struct sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);

        evconnlistener *listener;
        listener = evconnlistener_new_bind(_base, ListenerEventCallbackFun, this,
            LEV_OPT_LEAVE_SOCKETS_BLOCKING|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_THREADSAFE, -1,
            (struct sockaddr*)&sin, sizeof(sin));

        if (!listener) 
        {
            SetError("Could not create a listener!");
            return false;
        }

        //    创建LISTENER_INFO
        LISTENER_INFO<T> *p_listener_info = new LISTENER_INFO<T>();
        p_listener_info->_network_io = new T(*p_network_io);
        p_listener_info->_port = port;

        {
            //    加入列表
            Process::CAutoLock    lock(&_cs_map_listener);
            _map_listener[listener] = p_listener_info;
        }

        return true;
    }


    //    客户端模式
    template<typename T> 
    bool AddConnectEvent(std::string ip, unsigned short port, T *p_network_io)
    {
        NETWORK_INFO network_info;
        network_info._ip = ip;
        network_info._family = AF_INET;
        network_info._port = port;

        sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_addr.s_addr = inet_addr(ip.c_str());
        sin.sin_port = htons(port);
        sin.sin_family = AF_INET;    
    

        //    创建bufferevent
        bufferevent *bev;
        bev = bufferevent_socket_new(_base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS|BEV_OPT_THREADSAFE);
        if (!bev) 
        {
            SetError("[AddConnectEvent] Error constructing bufferevent!");
            return false;
        }

        //    创建数据处理对象
#ifdef _DEBUG
        printf("自动创建类:%s\n", typeid(T).name());
#endif
        CNetworkIO *p_network_io_new = new T(*p_network_io);
        p_network_io_new->Open(network_info, bev, this);

        //    设置事件回调
        bufferevent_setcb(bev, ReadCallbackFun, WriteCallbackFun, EventCallbackFun, p_network_io_new);
        bufferevent_enable(bev, EV_WRITE | EV_READ);

        if (bufferevent_socket_connect(bev, (struct sockaddr *)&sin, sizeof(sin)) != 0) 
        {
            /* Error starting connection */
            delete p_network_io_new;
            p_network_io_new = NULL;
            SetError("[AddConnectEvent] Error starting connection");
            return false;
        }
    
        {
            //    加入事件列表
            Process::CAutoLock    lock_network(&_cs_map_network_io);
            _map_network_io[network_info] = p_network_io_new;
        }

        return true;
    }

    //    删除连接事件
    bool DelConnectEvent(unsigned short port);

    bool DelConnectEvent(std::string ip, unsigned short port);

    //    获取错误信息(获取当前最后一次的错误描述)
    inline std::string GetError() 
    {
        Process::CAutoLock    lock(&_cs_err);
        return _err;
    }

    //    获取CNetworkIO引用
    inline CNetworkIO* GetNetworkIORef(const NETWORK_INFO &network_info)
    {
        CNetworkIO *networkio = NULL;        
        {
            Process::CAutoLock    lock_network(&_cs_map_network_io);
            std::map<NETWORK_INFO, CNetworkIO*>::iterator it = _map_network_io.find(network_info);
            if (it != _map_network_io.end())
            {
                networkio = (*it).second;
            }
        }
        
        if (networkio != NULL)
        {
            networkio->AddRef();
        }
        return networkio;
    }

    //    释放CNetworkIO引用
    inline bool PutNetworkIORef(const NETWORK_INFO &network_info)
    {
        CNetworkIO *networkio = NULL;        
        {
            Process::CAutoLock    lock_network(&_cs_map_network_io);
            std::map<NETWORK_INFO, CNetworkIO*>::iterator it = _map_network_io.find(network_info);
            if (it != _map_network_io.end())
            {
                networkio = (*it).second;
            }
        }

        if (networkio != NULL)
        {
            networkio->Colse();
        }
        return true;
    }

    //    获取连接列表
    inline VEC_NETWORK_INFO GetNetworkInfoList()
    {
        VEC_NETWORK_INFO vec_network_info;
        {
            Process::CAutoLock    lock_network(&_cs_map_network_io);
            std::map<NETWORK_INFO, CNetworkIO*>::iterator it = _map_network_io.begin();
            while(it != _map_network_io.end())
            {
                vec_network_info.push_back((*it).first);
                ++it;
            }
        }
        return vec_network_info;
    }

protected:
    //    线程函数
    unsigned int ThreadEntry(void);

private:
    CNetworkReactor(const CNetworkReactor &right);
    CNetworkReactor& operator=(const CNetworkReactor &right);

    //    关闭一个网络连接IO
    bool CloseNetworkIO();

    //    关闭网络连接事件回调
    bool CloseEventCallback(evutil_socket_t fd, short event, void *arg);

    //    监听事件回调
    bool ListenerEventCallback(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data);

    //    设置错误信息(设置为当前最后一次的错误描述)
    inline void SetError(char *err) 
    {
        Process::CAutoLock    lock(&_cs_err);
        _err = err;
    }

    friend class CNetworkIO;
    friend void CloseEventCallbackFun(evutil_socket_t fd, short event, void *arg);
    friend void ListenerEventCallbackFun(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data);

    //    数据部分
public:
protected:
private:
    Process::CCriticalSection                        _cs_map_network_io;
    std::map<NETWORK_INFO, CNetworkIO*>                _map_network_io;

    Process::CCriticalSection                        _cs_map_listener;
    std::map<evconnlistener*, LISTENER_INFO_BASE*>    _map_listener;        //    监听列表<监听指针,参数信息>

    event_base                                        *_base;
    Process::CCriticalSection                        _cs_err;    //    错误字符串锁
    std::string                                        _err;
    bool                                            _start;                //    是否启动
};

//    网络反应堆宏
#define NetRObj CSingleton<CNetworkReactor>::Instance()